require 'action_mailer'

# The BulkMail module contains the Job class, which does the actual
# bulk-mailing, and a convenience method to start a job.
module BulkMail
  class Mailer < ActionMailer::Base #:nodoc
    def msg(addr, sub, content, from_addr, c_type, additional_headers)
      recipients addr
      subject sub if sub
      body content
      from from_addr if from_addr
      content_type c_type if c_type
      headers additional_headers if additional_headers
    end
  end

  # The Job class performs the bulk-mailing work. Each instance starts a thread
  # That goes over the list of recipients and sends each one an email. A job
  # can also be queried for its progress, returning a number between 0 and 1.
  class Job
    attr_accessor :progress, :errors, :thread, :delivered, :total
    
    def initialize(opts)
      @recipients = IO.readlines(opts[:recipients_file])
      @subject = opts[:subject]
      @from = opts[:from]
      @content_type = opts[:content_type]
      @content = load_content(opts[:content_file])
      @progress = 0
      @delivered = 0
      @total = @recipients.size
      @errors = []
      @thread = Thread.new {process}
    end

    def load_content(fn)
      content = IO.readlines(fn)
      while line = content.shift
        break if line.empty?
        if line =~ /^(.+):\s?(.*)$/
          @headers ||= {}
          @headers[$1] = $2
        else
          content.unshift(line)
          break
        end
      end
      content.join
    end
    
    def process
      @recipients.each_with_index do |addr, idx|
        begin
          Mailer.deliver_msg(addr, @subject, @content, @from, @content_type, @headers)
          @progress = idx / @recipients.size
          @delivered += 1
          puts "Sent email to #{addr}"
        rescue => e
          puts e.message
          @errors << e
        end
      end
      @progress = 1
    end
  end
  
  def self.send(opts)
    Job.new(opts)
  end
  
  def self.server_settings
    ActionMailer::Base.server_settings
  end
end

